﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Aletfa.LightManager.Effects
{
    public class DamageEffect : IGameEffect
    {
        public DamageEffect()
        {
            this.Damages = new List<Damage>();
        }

        public DamageEffect(params Damage[] damages)
        {
            this.Damages = new List<Damage>(damages);
        }

        public bool IgnoreArmor { get; set; }

        /// <summary>
        /// Elenco dei danni da applicare
        /// </summary>
        public List<Damage> Damages { get; private set; }

        /// <inheritdoc />
        public string Perform(Unit target)
        {
            int total = 0;
            List<string> parts = new List<string>();
            foreach (DamageSources school in Enum.GetValues(typeof(DamageSources)))
            {
                if (!this.Damages.Any(d => d.Soruce == school)) continue;

                //tiro la resistenza
                if (DamageEffect.RollResistance(target, school))
                {
                    parts.Add(string.Format("<del>{0} danni {1}</del>", this.Damages.Where(d => d.Soruce == school).Sum(d => d.Number), school));
                    continue;
                }

                int armor = (this.IgnoreArmor) ? 0 : target.Armors[school]; //armatura rimanente
                List<Damage> source = this.Damages.Where(d => (d.Soruce == school) && !d.Aggravate).ToList();
                int sourceTotal = source.Sum(d => d.Number) - armor;
                if (sourceTotal > 0) total += sourceTotal;
                if (sourceTotal >= 0) armor = 0;
                string part = DamageEffect.Perform(target, new Damage() { Soruce = school, Number = sourceTotal, Aggravate = false });

                source = this.Damages.Where(d => (d.Soruce == school) && d.Aggravate).ToList(); //controllo gli aggravati poi
                sourceTotal = source.Sum(d => d.Number) - armor;
                if (sourceTotal > 0) total += sourceTotal;
                part += DamageEffect.Perform(target, new Damage() { Soruce = school, Number = sourceTotal, Aggravate = true });

                if (!string.IsNullOrEmpty(part.Replace("+", "")))
                    parts.Add(part);
            }

            string result = string.Format("{0} subisce {1} danni", target.Name, total);
            string subs = "";
            parts.ForEach(p => subs += p + " + ");
            if (!string.IsNullOrEmpty(subs))
                subs = string.Format("({0})", subs.Substring(0, subs.Length - 3));
            if (this.IgnoreArmor)
                subs += " (no armor)";
            return string.Format("{0} <font class='details'>{1}</font>", result, subs);
        }

        /// <summary>
        /// Tira una resistenza del bersaglio
        /// </summary>
        /// <param name="target"></param>
        /// <param name="school"></param>
        /// <returns>true se il bersaglio ha resistito alla magia</returns>
        private static bool RollResistance(Unit target, DamageSources school)
        {
            if (school == DamageSources.Phisical) return false;
            if (!target.IsEnemy) return false;
            if (target.Resistances[school] <= 0) return false;

            //tiro la resistenza
            int roll = new Random().Next(100);
            if (roll <= target.Resistances[school])
                return true;
            return false;
        }

        public string Undo(Unit target)
        {
            //eh... u cazz! qua è durissima
            throw new NotImplementedException();
        }

        private static string Perform(Unit target, Damage damage)
        {
            if (damage.Number <= 0) return "";

            string result = string.Format("{0} danni {1} {2}", damage.Number, (damage.Aggravate) ? "aggravati " : "", damage.Soruce);

            if (damage.Aggravate) //in caso di danni aggravati aggiungi in testa e scala
            {
                for (int i = 0; i < damage.Number; i++)
                    target.LifeStatus.Insert(0, WoundType.Aggravated);
                target.LifeStatus.RemoveRange(target.LifeStatus.Count - damage.Number, damage.Number);
                return result;
            }

            for (int i = 0; i < target.LifeStatus.Count; i++)
            {
                if (target.LifeStatus[i] != WoundType.Free) continue;
                target.LifeStatus[i] = WoundType.Wounded;
                damage.Number--;
                if (damage.Number == 0) break;
            }
            return result;
        }

        public bool IsTemporary
        {
            get { return false; }
        }

        /// <inheritdoc />
        public bool IsOneShot
        {
            get { return false; }
        }
    }
}
